/*
 * Copyright (C) 2010 Fores Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jp.fores.midori.core.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.Properties;

import org.apache.commons.io.IOUtils;

/**
 * プロパティ関連の処理を行うユーティリティクラス。<br>
 * (このクラスの全てのメソッドはスレッドセーフです。)<br>
 */
public class PropertyUtil {
	//==========================================================
	//メソッド

	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//コンストラクタ

	/**
	 * コンストラクタです。<br>
	 * (クラスメソッドのみのユーティリティークラスなので、privateにしてインスタンスを作成できないようにしています。)<br>
	 */
	private PropertyUtil() {
		//基底クラスのコンストラクタの呼び出し
		super();
	}


	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//クラスメソッド

	/**
	 * Readerの内容を元にしてプロパティのインスタンスを生成します。<br>
	 * 処理終了後、Readerは確実に閉じます。<br>
	 * 
	 * @param reader Reader
	 * @return プロパティのインスタンス
	 * @throws IOException 入出力エラーが発生した場合
	 */
	public static Properties getProperties(Reader reader) throws IOException {
		try {
			//プロパティのインスタンスを生成
			Properties properties = new Properties();

			//引数のReaderの内容を読み込む
			properties.load(reader);

			//生成したインスタンスを返す
			return properties;
		}
		//終了処理
		finally {
			//Readerを確実に閉じる
			IOUtils.closeQuietly(reader);
		}
	}

	/**
	 * 文字列の内容を元にしてプロパティのインスタンスを生成します。<br>
	 * 
	 * @param str 文字列
	 * @return プロパティのインスタンス
	 * @throws IOException 入出力エラーが発生した場合
	 */
	public static Properties getProperties(String str) throws IOException {
		//引数の文字列をStringReaderでラッピングして、実際に処理を行うメソッドを呼び出す
		return getProperties(new StringReader(str));
	}

	/**
	 * ファイルの内容を元にしてプロパティのインスタンスを生成します。<br>
	 * キーや値に日本語が含まれる場合でも、文字エンコーディングさえ正しければ、
	 * native2asciiをかけなくても文字化けすることなく読み込めます。<br>
	 * 
	 * @param file ファイル
	 * @param encoding 文字エンコーディング
	 * @return プロパティのインスタンス
	 * @throws IOException 入出力エラーが発生した場合
	 */
	public static Properties getProperties(File file, String encoding)
			throws IOException {
		//引数のファイルを指定された文字エンコーディングで読み込むためのReaderでラッピングして、実際に処理を行うメソッドを呼び出す
		return getProperties(new InputStreamReader(new BufferedInputStream(new FileInputStream(file)), encoding));
	}

	/**
	 * ファイルの内容を元にしてプロパティのインスタンスを生成します。<br>
	 * 文字エンコーディングにはUTF-8を指定します。<br>
	 * キーや値に日本語が含まれる場合でも、文字エンコーディングさえ正しければ、
	 * native2asciiをかけなくても文字化けすることなく読み込めます。<br>
	 * 
	 * @param file ファイル
	 * @return プロパティのインスタンス
	 * @throws IOException 入出力エラーが発生した場合
	 */
	public static Properties getProperties(File file) throws IOException {
		//文字エンコーディングにUTF-8を指定して、実際に処理を行うメソッドを呼び出す
		return getProperties(file, "UTF-8");
	}

	/**
	 * ファイルの内容を元にしてプロパティのインスタンスを生成します。<br>
	 * もし、ファイルが存在しない場合は、代わりに空の内容のプロパティのインスタンスを生成します。<br>
	 * キーや値に日本語が含まれる場合でも、文字エンコーディングさえ正しければ、
	 * native2asciiをかけなくても文字化けすることなく読み込めます。<br>
	 * 
	 * @param file ファイル
	 * @param encoding 文字エンコーディング
	 * @return プロパティのインスタンス
	 * @throws IOException 入出力エラーが発生した場合
	 */
	public static Properties getPropertiesIfFileNotExistsEmpty(File file,
			String encoding) throws IOException {
		//ファイルが存在する場合
		if (file.exists()) {
			//ファイルの内容を元にしてプロパティのインスタンスを生成するメソッドを呼び出す
			return getProperties(file, encoding);
		}
		//ファイルが存在しない場合
		else {
			//何も読み込まない状態のプロパティのインスタンスを生成して返す
			return new Properties();
		}
	}

	/**
	 * ファイルの内容を元にしてプロパティのインスタンスを生成します。<br>
	 * もし、ファイルが存在しない場合は、代わりに空の内容のプロパティのインスタンスを生成します。<br>
	 * 文字エンコーディングにはUTF-8を指定します。<br>
	 * キーや値に日本語が含まれる場合でも、文字エンコーディングさえ正しければ、
	 * native2asciiをかけなくても文字化けすることなく読み込めます。<br>
	 * 
	 * @param file ファイル
	 * @return プロパティのインスタンス
	 * @throws IOException 入出力エラーが発生した場合
	 */
	public static Properties getPropertiesIfFileNotExistsEmpty(File file)
			throws IOException {
		//文字エンコーディングにUTF-8を指定して、実際に処理を行うメソッドを呼び出す
		return getPropertiesIfFileNotExistsEmpty(file, "UTF-8");
	}

	/**
	 * プロパティのインスタンスからキーに対応する値をintとして取得します。<br>
	 * キーに対応する値が取得できなかった場合、または数値への変換に失敗した場合は例外を投げます。<br>
	 * 
	 * @param properties プロパティのインスタンス
	 * @param key キー
	 * @return キーに対応する値(int)
	 * @throws NumberFormatException 数値への変換に失敗した場合
	 */
	public static int getPropertyAsInt(Properties properties, String key)
			throws NumberFormatException {
		//キーに対応する値を取得
		String str = properties.getProperty(key);

		//キーに対応する値が取得できなかった場合
		if (str == null) {
			//例外を投げる
			throw new NumberFormatException("キーに対応する値が取得できませんでした。");
		}

		//キーに対応する値をintに変換して返す
		return Integer.parseInt(str);
	}

	/**
	 * プロパティのインスタンスからキーに対応する値をintとして取得します。<br>
	 * キーに対応する値が取得できなかった場合、または数値への変換に失敗した場合は、代わりに指定されたデフォルト値を返します。<br>
	 * 
	 * @param properties プロパティのインスタンス
	 * @param key キー
	 * @param defaultValue デフォルト値
	 * @return キーに対応する値(int)、またはデフォルト値
	 */
	public static int getPropertyAsInt(Properties properties, String key,
			int defaultValue) {
		try {
			//プロパティのインスタンスからキーに対応する値をintとして取得して返す
			return getPropertyAsInt(properties, key);
		}
		//例外処理
		catch (NumberFormatException e) {
			//代わりに指定されたデフォルト値を返す
			return defaultValue;
		}
	}

	/**
	 * プロパティのインスタンスからキーに対応する値をlongとして取得します。<br>
	 * キーに対応する値が取得できなかった場合、または数値への変換に失敗した場合は例外を投げます。<br>
	 * 
	 * @param properties プロパティのインスタンス
	 * @param key キー
	 * @return キーに対応する値(long)
	 * @throws NumberFormatException 数値への変換に失敗した場合
	 */
	public static long getPropertyAsLong(Properties properties, String key)
			throws NumberFormatException {
		//キーに対応する値を取得
		String str = properties.getProperty(key);

		//キーに対応する値が取得できなかった場合
		if (str == null) {
			//例外を投げる
			throw new NumberFormatException("キーに対応する値が取得できませんでした。");
		}

		//キーに対応する値をlongに変換して返す
		return Long.parseLong(str);
	}

	/**
	 * プロパティのインスタンスからキーに対応する値をlongとして取得します。<br>
	 * キーに対応する値が取得できなかった場合、または数値への変換に失敗した場合は、代わりに指定されたデフォルト値を返します。<br>
	 * 
	 * @param properties プロパティのインスタンス
	 * @param key キー
	 * @param defaultValue デフォルト値
	 * @return キーに対応する値(long)、またはデフォルト値
	 */
	public static long getPropertyAsLong(Properties properties, String key,
			long defaultValue) {
		try {
			//プロパティのインスタンスからキーに対応する値をlongとして取得して返す
			return getPropertyAsLong(properties, key);
		}
		//例外処理
		catch (NumberFormatException e) {
			//代わりに指定されたデフォルト値を返す
			return defaultValue;
		}
	}

}
